package com.bolt.report.engine.model;

import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.reflect.ObjectUtil;
import com.bolt.report.definition.StyleDefinition;
import com.bolt.report.engine.fill.FillDataSetElement;
import com.bolt.report.engine.fill.FillTextElement;
import com.bolt.report.exception.ReportException;
import com.bolt.report.util.ToolUtil;
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;
import java.awt.*;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;

public class BaseBand implements Serializable {

    protected Table table;

    public BaseBand() {
        this.table = new Table();
    }

    public void addColumn(Column column) {
        table.getColumns().add(column);
    }

    public void setColumns(List<Column> columns) {
        table.getColumns().clear();
        table.getColumns().addAll(columns);
    }

    public void setRows(List<Row> rows) {
        if (IteratorUtil.isNotEmpty(rows)) {
            for (int i = 0; i < rows.size(); i++) {
                Row row = rows.get(i);
                for (Cell cell : row.getCells()) {
                    if (null != cell) {
                        cell.setRowIndex(i);
                    }
                }
            }
            table.getRows().addAll(rows);
        }

    }

    public void appendRowCell(List<Cell> cells, int rowHeight) {
        int columnSize = getColumnSize();
        Row row = new Row(columnSize);
        row.setHeight(rowHeight);
        for (int i = 0; i < cells.size(); i++) {
            int index = cells.get(i).getColumnIndex();
            Column column = table.getColumns().get(index);
            Cell cell = cells.get(i);
            row.setCell(column, cell);
            doDataWrapCompute(row, cell);
        }
        table.getRows().add(row);
    }

    public void insertCell(Cell cell) {
        List<Row> rows = table.getRows();
        Row row = rows.get(cell.getRowIndex());
        row.setCell(cell);
        doDataWrapCompute(row, cell);
    }


    public void insertCells(List<Cell> cells, int rowHeight) {
        List<Row> rows = table.getRows();
        int columnSize = getColumnSize();
        int appendIndex = cells.size();

        for (int i = 0; i < cells.size(); i++) {
            Cell cell = cells.get(i);
            if (ObjectUtil.isNull(cell)) {
                continue;
            }
            int rowSize = rows.size();
            int columnIndex = cell.getColumnIndex();
            int rowIndex = cell.getRowIndex();
            if (rowIndex >= rowSize) {
                for (int k = rowSize; k <= rowIndex; ++k) {
                    Row newRow = new Row(columnSize);
                    newRow.setHeight(rowHeight);
                    rows.add(newRow);
                }
            }
            Row currentRow = rows.get(rowIndex);
            List<Cell> cellList = currentRow.getCells();


            Optional<Cell> exist = Optional.ofNullable(cellList.get(columnIndex));
            if (exist.isPresent()) {
                try {
                    Cell oldCell = (Cell) exist.get().clone();
                    cellList.set(columnIndex, cell);
                    appendIndex = appendIndex + 1;
                    if (appendIndex < cellList.size()) {
                        oldCell.setColumnIndex(appendIndex);
                        cellList.set(appendIndex, oldCell);
                    }
                } catch (CloneNotSupportedException e) {
                    throw new ReportException(e);
                }
            } else {
                cellList.set(columnIndex, cell);
            }
            doDataWrapCompute(currentRow, cell);
        }
    }


    public int getCurrentRowSize() {
        return table.getRows().size();
    }

    public Column getFirstColumn() {
        Column firstColumn = null;
        for (Column column : table.getColumns()) {
            if (column.isHide()) {
                continue;
            } else {
                firstColumn = column;
                break;
            }
        }
        return firstColumn;
    }

    public int getHideColumnSize() {
        int hideSize = 0;
        for (Column column : table.getColumns()) {
            if (column.isHide()) {
                hideSize++;
            }
        }
        return hideSize;
    }

    public int getRowIndex(Row row) {
        return this.getTable().getRows().indexOf(row);
    }


    public void insertLastRow(Row row) {
        table.getRows().add(row);
    }

    public int getColumnSize() {
        return this.table.getColumns().size();
    }

    public Table getTable() {
        return table;
    }

    public Row getRow(int rowIndex) {
        if (rowIndex >= table.getRows().size()) {
            throw new ReportException("Out Of row size {}:{}", String.valueOf(rowIndex), String.valueOf(table.getRows().size()));
        }
        return table.getRows().get(rowIndex);
    }

    public Row getLastRow() {
        int size = table.getRows().size();
        if (size == 0) {
            throw new ReportException("row is empty");
        }
        return table.getRows().get(size - 1);
    }

    public Cell getCell(int rowIndex, int columnIndex) {
        Row row = getRow(rowIndex);
        return row.getCell(columnIndex);
    }

    public void doDataWrapCompute(Row currentRow, Cell currentCell) {

        if (currentCell.getElement() instanceof FillTextElement || currentCell.getElement() instanceof FillDataSetElement) {
            Object targetData = currentCell.getElement().getValue();
            if (targetData == null || !(targetData instanceof String)) {
                return;
            }
            String dataText = targetData.toString();
            if (StringUtils.isBlank(dataText) || dataText.length() < 2) {
                return;
            }
            int columnIndex = currentCell.getColumnIndex();
            Column column = table.getColumn(columnIndex);
            int totalColumnWidth = column.getWidth();
            if (currentCell.getColSpan() > 0) {
                for (int i = 1; i < currentCell.getColSpan(); i++) {
                    Column col = table.getColumn(columnIndex + i);
                    totalColumnWidth += col.getWidth();
                }
            }
            StyleDefinition cellStyle = currentCell.getStyle();
            Font font = cellStyle.getFont();
            FontMetrics fontMetrics = new JLabel().getFontMetrics(font);
            int textWidth = fontMetrics.stringWidth(dataText);

            float singleLineHeight = ToolUtil.pointToPixel(fontMetrics.getHeight());//;
            if (textWidth <= totalColumnWidth) {
                return;
            }

            int totalLineHeight = 0;
            StringBuilder multipleLine = new StringBuilder();
            StringBuilder sb = new StringBuilder();
            int length = dataText.length();
            for (int i = 0; i < length; i++) {
                char text = dataText.charAt(i);
                if (text == '\r' || text == '\n') {
                    if (text == '\r') {
                        int nextIndex = i + 1;
                        if (nextIndex < length) {
                            char nextText = dataText.charAt(nextIndex);
                            if (nextText == '\n') {
                                i = nextIndex;
                            }
                        }
                    }
                    continue;
                }
                sb.append(text);
                int width = fontMetrics.stringWidth(sb.toString());
                if (width > totalColumnWidth) {
                    sb.deleteCharAt(sb.length() - 1);
                    totalLineHeight += singleLineHeight;
                    if (multipleLine.length() > 0) {
                        multipleLine.append('\n');
                    }
                    multipleLine.append(sb);
                    sb.delete(0, sb.length());
                    sb.append(text);
                }
            }
            if (sb.length() > 0) {
                totalLineHeight += singleLineHeight;
                if (multipleLine.length() > 0) {
                    multipleLine.append('\n');
                }
                multipleLine.append(sb);
            }
            currentCell.getElement().setValue(multipleLine.toString());
            int totalRowHeight = currentRow.getHeight();
            int rowSpan = currentCell.getRowSpan();
            if (rowSpan > 0) {
                int rowIndex = currentCell.getRowIndex();
                for (int i = 1; i < rowSpan; i++) {
                    Row targetRow = table.getRow(rowIndex + i);
                    totalRowHeight += targetRow.getHeight();
                }
            }
            int dif = totalLineHeight - totalRowHeight;
            if (dif > 0) {
                int rowHeight = currentRow.getHeight();
                currentRow.setRealHeight(rowHeight + dif);
            }
        }
    }

    public Row findLastRow() {
        int rowSize = getTable().getRows().size();
        if (rowSize > 0) {
            return table.getRows().get(rowSize - 1);
        } else {
            return null;
        }
    }


    public Row findRow(int index) {
        if (index < 0 || index > getTable().getRows().size()) {
            return null;
        }
        return table.getRows().get(1);
    }

}